package com.wl.tp;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * TCP Socket 服务器端
 * 
 * @author wangliang
 *
 */
public abstract class TCPServer implements Runnable {
	private int port;
	private boolean runFlag;
	private List<SocketTransceiver> clients = new ArrayList<>();
	
	public TCPServer(int port) {
		this.port = port;
	}
	
	public void start() {
		runFlag = true;
		new Thread(this).start();
	}
	
	public void stop() {
		runFlag = false;
	}

	@Override
	public void run() {
		try {
			final ServerSocket server = new ServerSocket(port);
			while (runFlag) {
				try {
					final Socket socket = server.accept();
					startClient(socket);
				} catch (IOException e) {
					// 接受客户端连接出错
					e.printStackTrace();
					this.onConnectFailed();
				}
			}
			
			// 停止服务器，断开与每个客户端的连接
			try {
				for(SocketTransceiver client : clients) {
					client.stop();
				}
				
				clients.clear();
				server.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		} catch (IOException e) {
			// ServerSocket对象创建出错，服务器启动失败
			e.printStackTrace();
		}
		
		this.onServerStop();
	}
	
	private void startClient(final Socket socket) {
		SocketTransceiver client = new SocketTransceiver(socket) {
			
			@Override
			public void onReceive(InetAddress addr, byte[] data) {
				TCPServer.this.onReceive(this, data);
				//TODO 要实现业务逻辑上的转发， 目前只是测试
				if(clients.size() > 1) {
					for(SocketTransceiver st : clients) {
						if(!st.addr.getHostAddress().equals(addr.getHostAddress())) {
							System.out.println(addr.getHostAddress() + " send to " + st.getInetAddress().getHostAddress());
							st.send(data);
						}
					}
				} else {
					System.out.println("目前只有一个人，所以不转发");
				}
			}
			
			@Override
			public void onDisconnect(InetAddress addr) {
				clients.remove(this);
				TCPServer.this.onDisconnect(this);
			}
		};
		
		client.start();
		clients.add(client);
		this.onConnect(client);
	}
	
	/**
	 * 客户端：连接建立
	 * <p>
	 * 注意：此回调是在新线程中执行的
	 * 
	 * @param client
	 *            SocketTransceiver对象
	 */
	public abstract void onConnect(SocketTransceiver client);

	/**
	 * 客户端：连接建立失败
	 * <p>
	 * 注意：此回调是在新线程中执行的
	 */
	public abstract void onConnectFailed();

	/**
	 * 客户端：收到字符串
	 * <p>
	 * 注意：此回调是在新线程中执行的
	 * 
	 * @param client
	 *            SocketTransceiver对象
	 * @param s
	 *            字符串
	 */
	public abstract void onReceive(SocketTransceiver client, byte[] s);

	/**
	 * 客户端：连接断开
	 * <p>
	 * 注意：此回调是在新线程中执行的
	 * 
	 * @param client
	 *            SocketTransceiver对象
	 */
	public abstract void onDisconnect(SocketTransceiver client);

	/**
	 * 服务器停止
	 * <p>
	 * 注意：此回调是在新线程中执行的
	 */
	public abstract void onServerStop();

}
